//
//  ASTypeParser.mm
//  FlashOutboard
//
//  Created by Martin Schiøth Dyrby on 1/30/11.
//  Copyright 2011 Molamil. All rights reserved.
//

#import "ASTypeParser.h"
#import "ATVInstance.h"
#import "ATVInstanceProperty.h"
#import "ATVInstanceNumericProperty.h"
#import "ATVInstanceStringProperty.h"
#import "ATVInstanceBooleanProperty.h"
#import "ATVInstanceObjectProperty.h"
#import "ATVInstanceSelectProperty.h"

static NSSet *accessorKeys;
static NSSet *childKeys;
static NSSet *numericTypes;
static NSSet *selectTypes;
static NSSet *stringTypes;
static NSSet *boolTypes;
static NSSet *methodKeys;
static NSSet *blackList;
static id <ATVInstanceProperty> currentMethod;
static NSString* currentMethodName;

@implementation ASTypeParser

@synthesize items;
@synthesize children;
@synthesize methods;
@synthesize declared;
@synthesize inherited;
@synthesize path;

+ (void)initialize
{
    if (!accessorKeys) {
        accessorKeys = [[NSSet alloc] initWithObjects: @"accessor", @"variable" ,nil];
    }
    if (!childKeys) {
        childKeys = [[NSSet alloc] initWithObjects: @"child" ,nil];
    }
    if (!numericTypes) {
        numericTypes = [[NSSet alloc] initWithObjects: @"int", @"uint", @"Number", nil];
    }
    
    if(!selectTypes) {
        selectTypes = [[NSSet alloc] initWithObjects: @"blendMode", nil];
    }
    
	if (!stringTypes) {
        stringTypes = [[NSSet alloc] initWithObjects: @"String", nil];
    }
	
	if (!boolTypes) {
        boolTypes = [[NSSet alloc] initWithObjects: @"Boolean", nil];
    }
	
	if (!methodKeys) {
		methodKeys = [[NSSet alloc] initWithObjects: @"method", nil];
	}
	
    if(!blackList) {
        blackList = [[NSSet alloc] initWithObjects: @"willTrigger", @"hasEventListener", @"getChildByName", @"contextMenu",@"getChildAt",nil];
    }
	
}



- (BOOL)parseData:(NSData *)d
{
    // Release the old itemArray
    [items release];
	[children release];
	[methods release];
	[declared release];
	[inherited release];
	path = nil;
	
    // Create a new, empty itemArray
    items = [[NSMutableArray alloc] init];
	children = [[NSMutableArray alloc] init];
	methods = [[NSMutableArray alloc] init];
	declared = [[NSMutableArray alloc] init];
	inherited = [[NSMutableArray alloc] init];
	
    // Create a parser
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:d];
    [parser setDelegate:self];
	
    // Do the parse
    [parser parse];
	
    [parser release];
    return YES;
}


- (NSArray *)parseItems
{
/*	[children sortUsingSelector:@selector(compare:)];
	[declared sortUsingSelector:@selector(compare:)];
	[inherited sortUsingSelector:@selector(compare:)];
	[methods sortUsingSelector:@selector(compare:)];*/
	
	for (int c = 0; c < [children count]; c++) {
		[items addObject: [children objectAtIndex: c]];
	}
	for (int d = 0; d < [declared count]; d++) {
		[items addObject: [declared objectAtIndex: d]];
	}
	for (int i = 0; i < [inherited count]; i++) {
		[items addObject: [inherited objectAtIndex: i]];
	}
	for (int m = 0; m < [methods count]; m++) {
		[items addObject: [methods objectAtIndex: m]];
	}
    
    [items sortUsingSelector:@selector(compare:)];
    
    return items;
}

- (void)parser:(NSXMLParser *)parser 
didStartElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI 
 qualifiedName:(NSString *)qualifiedName 
	attributes:(NSDictionary *)attributeDict {
	
	NSString* name;
	NSString* type;	
	BOOL insert = NO;
    
    if ([accessorKeys containsObject:elementName]) {
        
        id <ATVInstanceProperty> instanceProperty = nil;
		
		name = [attributeDict objectForKey:@"name"];

		type = [attributeDict objectForKey:@"type"];
		NSString* declaredBy = [attributeDict objectForKey:@"declaredBy"];
		
		if([elementName isEqualToString: @"accessor"]) {
			NSString* access = [attributeDict objectForKey:@"access"];
            
			insert = [access isEqualToString: @"readwrite"];
            
            if([selectTypes containsObject:name]) {
                instanceProperty = [[ATVInstanceSelectProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];                
            } else if([numericTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceNumericProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else if([stringTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceStringProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else if([boolTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceBooleanProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else{
                instanceProperty = [[ATVInstanceObjectProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			}
		} else{
			insert = YES;
			
			if([numericTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceNumericProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else if([stringTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceStringProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else if([boolTypes containsObject:type]) {
                instanceProperty = [[ATVInstanceBooleanProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			} else {
                instanceProperty = [[ATVInstanceObjectProperty alloc] init];
                [instanceProperty setName: name];
                [instanceProperty setType: type];
			}
		}
        
		if(insert){
            if(![blackList containsObject:instanceProperty.name]) {
                if(declaredBy != nil) {
                    if(instanceProperty != nil) [inherited addObject:instanceProperty];
                } else {
                    if(instanceProperty != nil) [declared addObject:instanceProperty];
                }
            }
		}
        
    } else if([childKeys containsObject:elementName]) {
        
		name = [attributeDict objectForKey:@"name"];

		type = [attributeDict objectForKey:@"type"];
        
        id <ATVInstanceProperty> child = [[ATVInstanceObjectProperty alloc] init];
        [child setName: name];
        [child setType: type];
		
        [children addObject:child];
	} else if ([elementName isEqualToString: @"type"]) {
		path = [attributeDict objectForKey:@"path"];
	} else if([methodKeys containsObject:elementName]) {
		currentMethodName = [attributeDict objectForKey:@"name"];
	} else if ([elementName isEqualToString:@"parameter"]) {
		if([[attributeDict objectForKey:@"index"] isEqualToString: @"1"]) {

            type = [attributeDict objectForKey:@"type"];
            if([numericTypes containsObject:type]) {
                currentMethod = [[ATVInstanceNumericProperty alloc] init];            
            } else if([stringTypes containsObject:type]) {
                currentMethod = [[ATVInstanceStringProperty alloc] init];            
            } else if([boolTypes containsObject:type]) {
                currentMethod = [[ATVInstanceBooleanProperty alloc] init];            
            } else {
                return;
            }

            [currentMethod setName: currentMethodName];
            [currentMethod setType: type];
            [currentMethod setIsMethod: YES];
            
		} else {
			currentMethod = nil;
		}
	}
}

- (void)parser:(NSXMLParser *)parser
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
    if([blackList containsObject:currentMethod.name]) {
        currentMethod = nil;
        return;
    }
	if([methodKeys containsObject:elementName] && currentMethod != nil) {
		[methods addObject:currentMethod];
		currentMethod = nil;
	}
}

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string
{
    
}

@end
